<script setup lang="ts">
import {
  Ref,
  computed,
  inject,
  onMounted,
  onUnmounted,
  ref,
  watch,
  watchEffect,
} from "vue";
import { useEventListener, useResizeObserver } from "@vueuse/core";
import { EChart } from "@/models/reactiveComponent";
import * as cpUtils from "./utils";

import * as injectKeys from "@/services/injectKeys";

const datasetServices = inject(injectKeys.datasetKey)!;
const sqlServices = inject(injectKeys.sqlAnalyzeKey)!;
const dbServices = inject(injectKeys.dbKey)!;
const cpServices = inject(injectKeys.componentKey)!;
const utilsServices = inject(injectKeys.utilsKey)!;
const webResourcesServices = inject(injectKeys.webResourcesServiceKey)!;

// const isfetched = ref(true)

const props = defineProps<{ model: EChart }>();
const model = props.model;

const mapFetchs = [] as Ref<boolean>[];
model.chartInfos.forEach((info) => {
  info?.mapIds.forEach((mapid) => {
    const isfetched = webResourcesServices.getResource(mapid) as Ref<boolean>;
    mapFetchs.push(isfetched);
  });
});

const allMapFetched = computed(() => mapFetchs.every((v) => v.value));

const filterUtils = cpUtils.getEChartsFilterUtils(model, {
  sqlAnalyze: sqlServices,
  dataset: datasetServices,
  db: dbServices,
  utils: utilsServices,
});

const appEventService = inject(injectKeys.appEventServiceKey)!;

function removeFilterOnHasClickInfo() {
  if (filterUtils.chartController.curController.value.hasClickInfo) {
    filterUtils.removeFilter();
  }
}

appEventService.onResetFilters(() => {
  removeFilterOnHasClickInfo();
});

const chartBox = ref(null as unknown as HTMLDivElement);
const chartOpt = filterUtils.getData();
const chartDiv = ref(null as unknown as HTMLDivElement);

const outterBoxHasNotHeightStyle = computed(() => {
  if (chartBox.value) {
    return chartBox.value.style.height === "";
  }

  return true;
});

const cssWidth = model.width;
const cssHeight = model.height;

let myChart: echarts.EChartsType | null = null;
onUnmounted(() => {
  myChart?.dispose();
});

watch([allMapFetched, chartDiv], ([isMapFetched, chartDiv]) => {
  if (!(isMapFetched && chartDiv)) {
    return;
  }

  myChart = echarts.init(chartDiv, null, {
    renderer: cpServices.getApp().echartsRenderer,
  });

  if (myChart === null) {
    return;
  }

  const chartIns = myChart;

  watchEffect(() => {
    filterUtils.chartController.setSeriesKeys(
      chartIns,
      chartOpt.value.series.map((v) => v.id)
    );
    chartIns.setOption(chartOpt.value, true);
  });

  chartIns.on("mouseover", "series", (params) => {
    if (!filterUtils.chartController.curController.value.hasClickInfo) {
      filterUtils.addFilter(params, "hover");
    }
  });

  chartIns.on("mouseout", "series", (params) => {
    // 没有 click info情况下，鼠标离开图形才需要移除。
    // 否则，这会影响点击选中的筛选
    if (!filterUtils.chartController.curController.value.hasClickInfo) {
      filterUtils.removeFilter();
    }
  });

  chartIns.getZr().on("click", function (event) {
    // 没有 target 意味着鼠标/指针不在任何一个图形元素上，它是从“空白处”触发的。
    if (!event.target) {
      removeFilterOnHasClickInfo();
    }
  });

  chartIns.on("click", "series", (params) => {
    if (model.debugTag !== null) {
      console.log("click filter:", params);
    }

    if (filterUtils.chartController.canForward.value) {
      const filterValue = filterUtils.addFilter(params, "click");
      filterUtils.chartController.next(chartIns, params, filterValue);
    } else {
      filterUtils.addFilter(params, "click");
    }
  });

  useEventListener("resize", () => {
    chartIns.resize();
  });

  useResizeObserver(chartDiv, () => {
    chartIns.resize();
  });
});

function onback() {
  filterUtils.removeFilter();
  filterUtils.chartController.back(myChart!);
}

const openOptViewBtnDisplay = model.debugTag !== null;
const optViewShowed = ref(false);

function onShowOptView() {
  optViewShowed.value = !optViewShowed.value;
}
</script>

<template>
  <div
    ref="chartBox"
    class="echart-box pybi-container"
    :data-tag="model.tag"
    data-pybi-auto-width
  >
    <div
      class="back"
      @click="onback"
      v-show="filterUtils.chartController.canBack.value"
    >
      上一级
    </div>
    <div class="debug-box" v-if="openOptViewBtnDisplay">
      <button @click="onShowOptView">options view open</button>
      <textarea rows="25" cols="50" readonly v-if="optViewShowed">{{
        chartOpt
      }}</textarea>
    </div>

    <div
      class="echart"
      ref="chartDiv"
      :class="{ 'min-height-chart': outterBoxHasNotHeightStyle }"
    ></div>
  </div>
</template>

<style scoped lang="less">
.pybi-flow-box > .echart-box > .echart {
  min-width: 30vw;
}

.echart-box {
  position: relative;
  width: 100%;
  height: 100%;

  .echart {
    width: 100%;
    height: v-bind(cssHeight);

    &.min-height-chart {
      min-height: 30vh;
    }
  }

  .debug-box {
    z-index: 9999;
    position: absolute;
    top: 0;
    left: 0;
    transform: translateY(-100%);

    display: flex;
    max-width: 100%;
  }

  .back {
    // position: absolute;
    z-index: 9999;

    display: inline-block;
    border: 1px solid #000;
    border-radius: 12%;
    padding: 0.2em;

    &:hover {
      cursor: pointer;
    }
  }
}
</style>
